package uk.ac.aber.paws.client.core;

import java.io.File;
import java.io.IOException;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;

import uk.ac.aber.paws.client.config.ConfigManager;
import uk.ac.aber.paws.client.constants.Constants;
import uk.ac.aber.paws.client.db.DBLogger;
import uk.ac.aber.paws.client.db.DBOperations;
import uk.ac.aber.paws.client.state.SystemState;
import uk.ac.aber.paws.client.updater.UpdateManager;
import uk.ac.aber.paws.client.util.WMIOperations;
import static uk.ac.aber.paws.client.constants.Constants.*;
import static uk.ac.aber.paws.client.constants.DatabaseLoggingConstants.*;

/**
 * @author Rob Johnson, Aberystwyth University
 * @email rob.johnson@aber.ac.uk
 * @date 8th August 2011
 * 
 * PAWSClient.java
 * 
 * This is the main class for the wrapper application. It performs the following operations:
 * 
 * a) Initialises application configuration from specified PAWS config file
 * b) Initialises SystemState that is used throughout the entire application
 * c) Starts all worker threads that perform all operations within the application
 * d) Parses cached database calls that were previously not logged to the database
 * e) Provides a procedure to cleanly shut down this application
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
public class PAWSClient {
	
	/**
	 * Stores the reference to the object containing the application system state
	 */
	public static SystemState SYSTEM_STATE;
	
	/**
	 * Stores the configuration for the application
	 */
	public static ConfigManager CONFIGURATION;
	
	public static PAWSThreads THREADS;
	
	
	/**
	 * Stores the path to the os configuration file
	 */
	public static Logger LOG_FILE;
	
	@SuppressWarnings("static-access")
	public static void main(String args[]) {
	
		// load the parameters
		try {
			
			// load configuration file - the path to this is expected as parameter 1
			String mainConfigPath = args[0];
			
			// load o/s specific file - the path to this is expected as parameter 2
			String osConfigPath = args[1];
			
			// load the log level - parameter 3
			String logLevel = args[2];
			
			// store the update flag
			String updatesFlag = "UPDATESON";
			
			if (args.length > 3) {
				updatesFlag = args[3];
			}
			
			// load the main configuration into CONFIGURATION
			loadConfiguration(mainConfigPath,osConfigPath);
			
			// starts the log file at the required debug level
			Logging.startLogFile(logLevel);
			
			// create a new SystemState object that stores various information about the running application
			SYSTEM_STATE = new SystemState();
			
			// initialise the login register
			SYSTEM_STATE.initialiseLoginRegister();
			
			// loops until all values contained in the Login object meet the required validation criteria 
			while (!SYSTEM_STATE.getComputerInfo().initSuccessful()) {
			
				Thread.currentThread().sleep(Integer.parseInt(CONFIGURATION.getProperty("app.main.processinterrupts.retryperiod"))*1000);
				Initiator.LOG_FILE.log(Level.CONFIG,"Retrying configuration procedure...");
				SYSTEM_STATE = new SystemState();
			}
			
			Initiator.LOG_FILE.log(Level.CONFIG,"Initiated System State successfully");
			
			// print application initialisation to file
			Logging.logInitialisationInfo();
			
			// check for update
			boolean restartRequired = false;
			
			// disable updates for linux and MAC for the time being...
			if (updatesFlag.equals("UPDATESON")) {
				
				restartRequired = UpdateManager.checkForNewUpdates();
				
				if (restartRequired) {
					Initiator.LOG_FILE.log(Level.CONFIG,"Updates applied....restarting");
					
					Operations.cleanCloseDown(true);
				}
			}
			else {	
				Initiator.LOG_FILE.log(Level.CONFIG,"No new updates found");
			}
			
			// start the guts of the application...
			THREADS = new PAWSThreads();
			
			// once initialise, start the health check thread
			THREADS.startHealthCheckThread();
			
			// register startup of service to database
			(new DBLogger()).registerPowerEvent(SYSTEM_STATE.getComputerInfo().getComputerName(),CLIENT_SERVICE_START,new Timestamp(Calendar.getInstance().getTimeInMillis()));
			
			// register the mac address and ip address for this computer
			(new DBLogger()).registerNetworkCreds();
		}
		catch (IndexOutOfBoundsException ex) {
			System.out.println("PROGRAM ERROR: Config file not specified...exiting");
			System.exit(1);
		}
		catch (Exception ex) {
			Initiator.LOG_FILE.log(Level.INFO,ex.toString());
		}
		
	}
	
	public static void loadConfiguration(String mainConfigPath, String osConfigPath) {
	
		if (new File(mainConfigPath).exists()) {
			CONFIGURATION = new ConfigManager(mainConfigPath,osConfigPath,false);
		}
		//if the paws.conf,does not exist i.e. a new installation - download it.
		else {
			
		}
	}
	
	public static PAWSThreads getThreads() {
		return THREADS;
	}
	
	/**
	 * This function is ran when the wrapper service is stopped 
	 */
	public static void stop(String code) {
		
		// log the PAWS Client service restart to the database
		if (code.equals(WINDOWS_SERVICE_SERVICERESTART_CODE)) {
			(new DBLogger()).registerPowerEvent(SYSTEM_STATE.getComputerInfo().getComputerName(),"CLIENT_SERVICE_STOP",new Timestamp(Calendar.getInstance().getTimeInMillis()));
		}
		// log the manual shutdown event to the database for this computer
		else if (code.equals(WINDOWS_SERVICE_SHUTDOWN_CODE)) {
			(new DBLogger()).registerPowerEvent(SYSTEM_STATE.getComputerInfo().getComputerName(),"CLIENT_SHUTDOWN",new Timestamp(Calendar.getInstance().getTimeInMillis()));
		}
			
		// delete the service shutdown file - which allows the wrapper service to close down properly
		if ((new File(CONFIGURATION.getProperty("wrapper.app.shutdown.status")).exists())) {
			((new File(CONFIGURATION.getProperty("wrapper.app.shutdown.status")))).delete();
		}
		
		PAWSClient.SYSTEM_STATE.getLoginRegister().logOutAllUsers();
		
		THREADS.stopThreads();
		
		// instruct the db call queue to empty - if possible
		DBOperations.parseQueuedDBCalls();
		
		// save the cachedDBcalls object to file
		DBOperations.saveCheckDBCallsToFile();
		
	}

	public static ConfigManager getConfig() {
		
		return CONFIGURATION;
	}

}
